#include "cmd.h"
#include "string.h"
#include "stdlib.h"

#ifdef FINSH_USING_MSH

typedef int (*cmd_function_t)(const char *fmt, ...);

typedef struct {
    char name[20];
    cmd_function_t function;
}cmd_list_t;

void cmd_error(const char *cmd_line);
int cmd_help(const char *cmd_line);
int cmd_hello(const char *cmd_line);
int cmd_version(const char *cmd_line);
int cmd_add(const char *cmd_line);
int cmd_sub(const char *cmd_line);
int cmd_mul(const char *cmd_line);
int cmd_div(const char *cmd_line);

#define CMD_LIST_MAX 10

uint8_t cmd_cnt = 0;
cmd_list_t cmd_list[CMD_LIST_MAX];

extern void shell_screen_append(uint8_t mode, char *line_data, uint8_t line_len);

void cmd_init(void)
{
    memcpy(cmd_list[0].name, "help", sizeof("help"));
    cmd_list[0].function = cmd_help;
    memcpy(cmd_list[1].name, "hello", sizeof("hello"));
    cmd_list[1].function = cmd_hello;
    memcpy(cmd_list[2].name, "version", sizeof("version"));
    cmd_list[2].function = cmd_version;
    memcpy(cmd_list[3].name, "add", sizeof("add"));
    cmd_list[3].function = cmd_add;
    memcpy(cmd_list[4].name, "sub", sizeof("sub"));
    cmd_list[4].function = cmd_sub;
    memcpy(cmd_list[5].name, "mul", sizeof("mul"));
    cmd_list[5].function = cmd_mul;
    memcpy(cmd_list[6].name, "div", sizeof("div"));
    cmd_list[6].function = cmd_div;
    cmd_cnt = 7;
}

de_bool_t cmd_is_used(void)
{
    return DE_TRUE;
}

float powff(float x, int n)  //  x的n次方
{
    float result = 1;

    while(n--)
    {
        result *= x;
    }

    return result;
}

int str2float(char *pStr, float *dl)  // 字符串转float型
{
    float  Num = 0;
    uint8_t BitBehidePoint = 0;
    uint8_t leng = 0;
    uint8_t PointCount = 0;
    while(pStr[leng] != '\0')  // 遍历
    {
        if ((pStr[leng] >= '0' && pStr[leng] <= '9') || pStr[leng] == '.') // 合法字符判定
        {
            if(pStr[leng] != '.' && !PointCount )      // 整数部分处理
            {
                Num = Num*10 + (pStr[leng]-'0');
            }
            else if(PointCount )  // 小数部分处理
            {
                BitBehidePoint ++;
                Num += (pStr[leng] - '0') * powff(0.1, BitBehidePoint);
            }
            if(pStr[leng] == '.') // 计数.的数量，若大于1个则为非法字符串
            {
                PointCount ++;
                if(PointCount  >= 2)
                {
                    // printf("More point error \r\n");
                    return -2;
                }
            }
        }
        else // 字符串中含有非法字符
        {
            // printf(" error sysm type \r\n");
            return -1;
        }
        leng ++;  // 计算字符串长度
    }
    // printf("the Strings’s leng is: %d  \r\n",leng);
    *dl = Num;
    return 0;
}

// int cmd_check_float(const char *cmd_param, float *fl)
// {
//     uint8_t cnt = 0;
//     uint8_t point_cnt = 0;
//     float ret_float = 0;
//     char *pEnd;

//     while(*cmd_param != '\0')
//     {
//         if(*cmd_param >= '0' && *cmd_param <= '9')
//         {

//         }
//         else if(*cmd_param == '.')
//         {
//             point_cnt++;
//             if(point_cnt > 1)
//             {
//                 return -1;
//             }
//         }
//         else if(*cmd_param == '-')
//         {
//             if(cnt > 0)
//             {
//                 return -2;
//             }
//         }
//         else
//         {
//             return -3;
//         }
//         cnt++;
//         cmd_param++;
//     }
//     return 0;
// }

void cmd_exec(char *cmd_line, uint8_t cmd_len)
{
    if(cmd_len > 0)
    {
        uint8_t i = 0;
        char cmd_line_temp[30] = {0};

        memcpy(cmd_line_temp, cmd_line, cmd_len);
        for(i = 0;i < cmd_cnt;i++)
        {
            if(memcmp(cmd_list[i].name, cmd_line_temp, strlen(cmd_list[i].name)) == 0 && cmd_len >= strlen(cmd_list[i].name))
            {
                cmd_list[i].function(cmd_line_temp);
                //printf("ret:%d\r\n", cmd_list[i].function(cmd_line_temp));
                break;
            }
        }
        if(i == cmd_cnt)
        {
            cmd_error(cmd_line_temp);
        }
    }
}

void cmd_complete(char *cmd_line)
{
    int i;
    for(i = 0;i < cmd_cnt;i++)
    {
        if(memcmp(cmd_list[i].name, cmd_line, strlen(cmd_line)) == 0)
        {
            memcpy(cmd_line, cmd_list[i].name, strlen(cmd_list[i].name));
        }
    }
}

int cmd_split(const char *cmd_line, char cmd_array[][10])
{
    uint8_t status = 0;
    uint8_t param_num = 0;
    uint8_t param_cnt = 0;
    while(*cmd_line != '\0')
    {
        if(status == 0)
        {
            if(*cmd_line != ' ')
            {
                cmd_array[param_num][param_cnt++] = *cmd_line;
            }
            else
            {
                status = 1;
            }  
        }
        else if(status == 1)
        {
            if(*cmd_line != ' ')
            {
                status = 0;
                param_cnt = 0;
                param_num++;
                cmd_array[param_num][param_cnt++] = *cmd_line;
            }
        }
        cmd_line++;
    }

    return param_num + 1;
}

void cmd_error(const char *cmd_line)
{
    char print_datap[100] = {0};

    sprintf(print_datap, "\"%s\" command error", cmd_line);
    printf("%s\r\n", print_datap);
    shell_screen_append(1, print_datap, strlen(print_datap));
    cmd_help("help\0");
}

int cmd_help(const char *cmd_line)
{
    uint8_t i = 0;
    char cmd_array[10][10];
    char print_datap[100] = {0};

    if(cmd_split(cmd_line, cmd_array) > 1)
    {
        cmd_error(cmd_line);
        return -1;
    }

    printf("cmd command have: ");
    sprintf(print_datap, "cmd command have: ");
    for(i = 0;i < cmd_cnt;i++)
    {
        printf("%s ", cmd_list[i].name);
        sprintf(&print_datap[strlen(print_datap)], "%s ", cmd_list[i].name);
    }
    shell_screen_append(1, print_datap, strlen(print_datap));
    printf("\r\n");
    return 0;
}

int cmd_hello(const char *cmd_line)
{
    char cmd_array[10][10];
    char print_datap[100] = {0};

    if(cmd_split(cmd_line, cmd_array) > 1)
    {
        cmd_error(cmd_line);
        return -1;
    }

    sprintf(print_datap, "hello DE-RTOS!");
    shell_screen_append(1, print_datap, strlen(print_datap));
    printf("%s\r\n", print_datap);
    return 0;
}

int cmd_version(const char *cmd_line)
{
    char cmd_array[10][10];
    char print_datap[100] = {0};

    if(cmd_split(cmd_line, cmd_array) > 1)
    {
        cmd_error(cmd_line);
        return -1;
    }
    sprintf(print_datap, "version:V1.0.0");
    shell_screen_append(1, print_datap, strlen(print_datap));
    printf("%s\r\n", print_datap);
    return 0;
}

int cmd_add(const char *cmd_line)
{
    int i;
    int param_num = 0;
    char cmd_array[10][10] = {0};
    float cmd_float[10] = {0};
    float result = 0;
    char print_datap[100] = {0};

    param_num = cmd_split(cmd_line, cmd_array);
    if(param_num < 2 || param_num > 3)
    {
        cmd_error(cmd_line);
        return -1;
    }

    for(i = 1;i < param_num;i++)
    {
        // printf("%s\r\n", cmd_array[i]);
        if(str2float(cmd_array[i], &cmd_float[i - 1]) != 0)
        {
            cmd_error(cmd_line);
            return -2;
        }
    }

    result = cmd_float[0] + cmd_float[1];
    sprintf(print_datap, "add result:%f", result);
    shell_screen_append(1, print_datap, strlen(print_datap));
    printf("add result:%f\r\n", result);
    return 0;
}

int cmd_sub(const char *cmd_line)
{
    int i;
    int param_num = 0;
    char cmd_array[10][10] = {0};
    float cmd_float[10] = {0};
    float result = 0;
    char print_datap[100] = {0};

    param_num = cmd_split(cmd_line, cmd_array);
    if(param_num < 2 || param_num > 3)
    {
        cmd_error(cmd_line);
        return -1;
    }

    for(i = 1;i < param_num;i++)
    {
        // printf("%s\r\n", cmd_array[i]);
        if(str2float(cmd_array[i], &cmd_float[i - 1]) != 0)
        {
            cmd_error(cmd_line);
            return -2;
        }
    }

    result = cmd_float[0] - cmd_float[1];
    sprintf(print_datap, "sub result:%f", result);
    shell_screen_append(1, print_datap, strlen(print_datap));
    printf("sub result:%f\r\n", result);
    return 0;
}

int cmd_mul(const char *cmd_line)
{
    int i;
    int param_num = 0;
    char cmd_array[10][10] = {0};
    float cmd_float[10] = {0};
    float result = 0;
    char print_datap[100] = {0};

    param_num = cmd_split(cmd_line, cmd_array);
    if(param_num < 2 || param_num > 3)
    {
        cmd_error(cmd_line);
        return -1;
    }

    for(i = 1;i < param_num;i++)
    {
        // printf("%s\r\n", cmd_array[i]);
        if(str2float(cmd_array[i], &cmd_float[i - 1]) != 0)
        {
            cmd_error(cmd_line);
            return -2;
        }
    }

    result = cmd_float[0] * cmd_float[1];
    sprintf(print_datap, "mul result:%f", result);
    shell_screen_append(1, print_datap, strlen(print_datap));
    printf("mul result:%f\r\n", result);
    return 0;
}

int cmd_div(const char *cmd_line)
{
    int i;
    int param_num = 0;
    char cmd_array[10][10] = {0};
    float cmd_float[10] = {0};
    float result = 0;
    char print_datap[100] = {0};

    param_num = cmd_split(cmd_line, cmd_array);
    if(param_num < 2 || param_num > 3)
    {
        cmd_error(cmd_line);
        return -1;
    }

    for(i = 1;i < param_num;i++)
    {
        // printf("%s\r\n", cmd_array[i]);
        if(str2float(cmd_array[i], &cmd_float[i - 1]) != 0)
        {
            cmd_error(cmd_line);
            return -2;
        }
    }

    if(cmd_float[1] == 0)
    {
        cmd_error(cmd_line);
        return -2;
    }

    result = cmd_float[0] / cmd_float[1];
    sprintf(print_datap, "div result:%f", result);
    shell_screen_append(1, print_datap, strlen(print_datap));
    printf("div result:%f\r\n", result);
    return 0;
}

#endif
